package com.pumpkin.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.BaseAdapter;

import com.pumpkin.baseui.R;

import java.util.ArrayList;
import java.util.List;

public class FlowLayout extends ViewGroup {

    private Table mTable;
    private BaseAdapter mAdapter;
    private OnItemClickListener mItemClickListener;
    private int INVALID_POSITION = -1;
    private int COLUMN_AUTO_FIT = -1;
    private OnClickListenerItem mClickListener;
    private boolean vertical_divider;
    private boolean horizontal_divider;
    private Paint mDividerPaint;
    private float mNumColumn = COLUMN_AUTO_FIT;
    private float dividerHeight;
    private int mMaxLine = Integer.MAX_VALUE;
    private int mGravity = Gravity.START;

    public class Gravity {
        public static final int START = 0x000001;
        public static final int CENTER_HORIZONTAL = 0x000010;
        public static final int END = 0x000100;
    }

    // item 点击事件
    public interface OnItemClickListener {
        void onItemClick(View v, int position);
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        mItemClickListener = listener;
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);

    }

    public FlowLayout(Context context) {
        super(context);
    }

    private void init(Context context, AttributeSet attrs) {
        setWillNotDraw(false);//
        TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
        vertical_divider = attr.getBoolean(R.styleable.FlowLayout_vertical_divider, false);
        horizontal_divider = attr.getBoolean(R.styleable.FlowLayout_horizontal_divider, false);
        mNumColumn = attr.getFloat(R.styleable.FlowLayout_numColumn, COLUMN_AUTO_FIT);
        dividerHeight = attr.getDimension(R.styleable.FlowLayout_divider_height, 0);
        mGravity = attr.getInt(R.styleable.FlowLayout_content_gravity, Gravity.START);
        mMaxLine = attr.getInt(R.styleable.FlowLayout_maxLine, Integer.MAX_VALUE);
        attr.recycle();
        // setOnHierarchyChangeListener(new OnHierarchyChangeListener() {
        // @Override
        // public void onChildViewRemoved(View parent, View child) {
        //
        // }
        //
        // @Override
        // public void onChildViewAdded(View parent, View child) {
        // if (mClickListener == null) {
        // mClickListener = new OnClickListenerItem();
        // }
        // child.setOnClickListener(mClickListener);
        // }
        // });
        mDividerPaint = new Paint();
        mDividerPaint.setAntiAlias(true);
        mDividerPaint.setColor(0xFFd8d9db);
    }

    class OnClickListenerItem implements OnClickListener {
        @Override
        public void onClick(View v) {
            int position = getPositionForView(v);
            if (mItemClickListener != null) {
                mItemClickListener.onItemClick(v, position);
            }
        }
    }

    public int getPositionForView(View view) {
        View listItem = view;
        try {
            View v;
            while (!(v = (View) listItem.getParent()).equals(this)) {
                listItem = v;
            }
        } catch (ClassCastException e) {
            return INVALID_POSITION;
        }
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            if (getChildAt(i).equals(listItem)) {
                return i;
            }
        }

        return INVALID_POSITION;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        float maxWidth = getMeasuredWidth();
        if (changed && maxWidth <= 0) {
            int height = 0;
            int count = getChildCount();
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (mTable == null) {
                    mTable = new Table(r - l, this);
                }
                mTable.resetMeasure(r - l, this);
                height = mTable.addElement(child);
            }
            // Log.e("", "width:" + width + "   height:" + height);
            setMeasuredDimension(0, height);
        }
        if (mTable != null) {
            mTable.layout();
        }
    }

    public void setAdapter(BaseAdapter adapter) {
        if (adapter == null) {
            return;
        }
        adapter.registerDataSetObserver(new DataSetObserver() {
            @Override
            public void onChanged() {
                super.onChanged();
                resetData();
            }
        });
        this.mAdapter = adapter;
        resetData();
    }

    List<View> childs = new ArrayList<View>();

    private void resetData() {
        removeAllViews();
        childs.clear();
        if (mTable != null) {
            childs.addAll(mTable.getChilds());
            mTable.resetMeasure(getMeasuredWidth(), this);
            for (int i = 0; i < mAdapter.getCount(); i++) {
                View child = null;
                if (childs.size() > i) {
                    child = childs.get(i);
                }
                View view = mAdapter.getView(i, child, this);
                ViewParent parent = view.getParent();
                if (parent instanceof ViewGroup) {
                    ((ViewGroup) parent).removeView(view);
                }
                addView(view);
            }
        } else {
            for (int i = 0; i < mAdapter.getCount(); i++) {
                View child = null;
                View view = mAdapter.getView(i, child, this);
                ViewParent parent = view.getParent();
                if (parent instanceof ViewGroup) {
                    ((ViewGroup) parent).removeView(view);
                }
                addView(view);
            }
        }
        requestLayout();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        drawVerticalDivider(canvas);
        drawHorizontalDivider(canvas);
    }

    private void drawVerticalDivider(Canvas canvas) {
        if (mTable != null && vertical_divider) {
            List<Line> lines = mTable.getLines();
            int cacheHeight = getPaddingTop();

            // 最后一条不画
            for (int i = 0; i < lines.size() - 1; i++) {
                Line line = lines.get(i);
                float height = line.getHeight();
                cacheHeight += height;
                canvas.drawRect(0, cacheHeight, getWidth(), cacheHeight + dividerHeight, mDividerPaint);
//                canvas.drawLine(0, cacheHeight, getWidth(), cacheHeight, mDividerPaint);
            }
        }
    }

    private void drawHorizontalDivider(Canvas canvas) {
        if (mNumColumn > 1 && horizontal_divider) {
            float cacheWidth = 0;
            float columWidth = getWidth() * 1f / mNumColumn * 1f;
            for (int i = 0; i < mNumColumn - 1; i++) {
                cacheWidth += columWidth;
                canvas.drawLine(cacheWidth, 0, cacheWidth, getHeight(), mDividerPaint);
            }
        }
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = getChildCount();
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = 0;
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, LayoutParams.WRAP_CONTENT);
            int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, LayoutParams.WRAP_CONTENT);

            if (mNumColumn > 0) {
                childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, (int) ((width * 1f- paddingLeft - paddingRight) / mNumColumn));
            } else {

            }
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            // if (singleColumn) {
            // } else {
            // child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
            // }
            if (mTable == null) {
                mTable = new Table(width- paddingLeft - paddingRight, this);
            }
            height = mTable.addElement(child);
        }
        // Log.e("", "width:" + width + "   height:" + height);
        setMeasuredDimension(width, height);
//        ViewUtils.measureView(this);
    }

    public class Line {
        private float maxHeight;
        private float mCacheWidth;
        private float maxWidth;
        private int mTop;
        private int mLeft;
        private int mRight;
        private boolean isEnd;
        private List<View> views = new ArrayList<>();

        public void setTop(int top) {
            this.mTop = top;
        }

        public void setMaxWidth(float width) {
            maxWidth = width;
        }

        public void setRight(int right) {
            this.mRight = right;
        }

        public void setLeft(int left) {
            this.mLeft = left;
        }

        public float getHeight() {
            return maxHeight;
        }

        public void layout() {
            switch (mGravity) {
                case Gravity.START:
                    layoutStart();
                    break;
                case Gravity.CENTER_HORIZONTAL:
                    layoutCenter();
                    break;
                case Gravity.END:
                    layoutEnd();
                    break;
                default:
                    layoutStart();
                    break;
            }

        }

        private void layoutStart() {
            int cacheWidth = mLeft;
            for (View child : views) {
                int width = child.getMeasuredWidth();
                int height = child.getMeasuredHeight();
                int top = (int) (mTop + ((maxHeight - height) / 2f));
                child.layout(cacheWidth, top, cacheWidth + width, top + height);
                cacheWidth += width;
            }
        }

        private void layoutCenter() {
            int cacheWidth = (int) ((maxWidth - mCacheWidth) / 2f) + mLeft;
            for (View child : views) {
                int width = child.getMeasuredWidth();
                int height = child.getMeasuredHeight();
                int top = (int) (mTop + ((maxHeight - height) / 2f));
                child.layout(cacheWidth, top, cacheWidth + width, top + height);
                cacheWidth += width;
            }
        }

        private void layoutEnd() {
            int cacheWidth = mRight;
            for (View child : views) {
                int width = child.getMeasuredWidth();
                int height = child.getMeasuredHeight();
                int top = (int) (mTop + ((maxHeight - height) / 2f));
                child.layout(cacheWidth - width, top, cacheWidth, top + height);
                cacheWidth -= width;
            }
        }


        public float addElement(View element) {
            int width = element.getMeasuredWidth();
            int height = element.getMeasuredHeight();
            if ((mCacheWidth + width) > maxWidth || isEnd) {
                if (views.size() > 0) {
                    isEnd = true;
                    return -1;
                }
            }
            if (height > maxHeight) {
                maxHeight = height + dividerHeight;
            }
            mCacheWidth += width;
            views.add(element);
            return maxHeight;
        }
    }

    public class Table {
        float maxWidth;
        float mTop;
        float mLeft;
        float mBottom;
        float cacheLineHeight;
        float mRight;
        private boolean singleColumn = false;
        // Map<View, Line> mapLines = new HashMap<View, AutoLineView.Line>();
        List<Line> lines = new ArrayList<>();
        List<View> elements = new ArrayList<>();

        public void resetMeasure(float width, View parent) {
            cacheLineHeight = 0;
            elements.clear();
            lines.clear();
            maxWidth = width ;//- parent.getPaddingLeft() - parent.getPaddingRight();
            mTop = parent.getPaddingTop();
            mLeft = parent.getPaddingLeft();
            mRight = getPaddingRight();
            mBottom = parent.getPaddingBottom();
        }

        public float getMaxWidth() {
            return maxWidth;
        }

        public Table(float width, View parent) {
            maxWidth = width;// - parent.getPaddingLeft() - parent.getPaddingRight();
            mTop = parent.getPaddingTop();
            mLeft = parent.getPaddingLeft();
            mRight = getPaddingRight();
            mBottom = parent.getPaddingBottom();
        }

        public void setSingleColumn(boolean single) {
            singleColumn = single;
        }

        public void layout() {
            for (Line line : lines) {
                line.layout();
            }
        }

        private int getHeight() {
            return (int) (mTop + cacheLineHeight + mBottom);
        }

        public List<Line> getLines() {
            return lines;
        }

        public List<View> getChilds() {
            return elements;
        }

        public int addElement(View element) {
            boolean contains = elements.contains(element);
            if (contains) {
                return getHeight();
            }
            elements.add(element);
            Line line = getLastLine();
            float tempHeight = line.addElement(element);

            if (tempHeight == -1f || singleColumn) {
                if (lines.size() == mMaxLine) {
                    return getHeight();
                }
                Line newLine = createLine();
                tempHeight = newLine.addElement(element);
                // lines.add(newLine);
            }
            cacheLineHeight = tempHeight;
            return getHeight();
        }

        private Line createLine() {
            mTop += cacheLineHeight;
            Line line = new Line();
            line.setTop((int) mTop);
            line.setLeft((int) mLeft);
            line.setRight((int) mRight);
            line.setMaxWidth(maxWidth);
            lines.add(line);
            return line;
        }

        private Line getLastLine() {
            if (lines.size() > 0) {
                return lines.get(lines.size() - 1);
            }
            return createLine();
        }

    }

}
